package gameserver.model.gameobjects.stats;

import gameserver.dataholders.PlayerStatsData;
import gameserver.model.gameobjects.player.Player;
import gameserver.model.gameobjects.stats.id.ItemStatEffectId;
import gameserver.model.gameobjects.stats.id.StatEffectId;
import gameserver.model.gameobjects.stats.modifiers.StatModifier;
import gameserver.model.items.ItemSlot;


import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.Map.Entry;

import org.apache.log4j.Logger;

public class PlayerGameStats
{
	private static Logger logger = Logger.getLogger(PlayerGameStats.class);
	
	protected Map<StatEnum, Stat> stats;
	protected Map<StatEffectId, TreeSet<StatModifier>> statsModifiers;

    protected Player owner;
    
    public PlayerGameStats(Player _owner)
    {
    	this.owner = _owner;
    	this.stats = Collections.synchronizedMap(new HashMap<StatEnum, Stat>());
    	this.statsModifiers = Collections.synchronizedMap(new HashMap<StatEffectId, TreeSet<StatModifier>>());
    }
    
    public PlayerGameStats(PlayerStatsData playerStatsData,final Player owner)
    {
    	
    }
    
    public void setStat(StatEnum stat, int value) {
        setStat(stat, value, false);
    }

    public int getBaseStat(StatEnum stat) {
        if (stats.containsKey(stat))
            return stats.get(stat).getBase();
        else
            return 0;
    }
    
    public void endEffect(StatEffectId id)
    {
    	statsModifiers.remove(id);
    	recomputeStats();
    }
    
    
    public int getCurrentStat(StatEnum stat) {
        if (stats.containsKey(stat)) {
            Stat statObject = stats.get(stat);
            if (statObject == null)
                return 0;
            else
                return statObject.getCurrent();
        }
        else
            return 0;
    }
    
    public int getOldStat(StatEnum stat) {
        if (stats.containsKey(stat))
            return stats.get(stat).getOld();
        else
            return 0;
    }
    
    public void addModifiers(StatEffectId id, TreeSet<StatModifier> modifiers) {
        if (modifiers == null || statsModifiers.containsKey(id))
            return;

        statsModifiers.put(id, modifiers);
        recomputeStats();
    }

	private void recomputeStats()
	{
		// TODO Auto-generated method stub
		resetStats();
		Map<StatEnum, StatModifiers> orderedModifiers = new HashMap<StatEnum, StatModifiers>();
		
		synchronized (statsModifiers)
		{
			for(Entry<StatEffectId, TreeSet<StatModifier>> modifiers : statsModifiers.entrySet())
			{
				if(modifiers.getValue() == null)
					continue;
				for(StatModifier modifier : modifiers.getValue())
				{
					List<StatEnum> statToModifiers = new ArrayList<StatEnum>();
					if(modifier.getStatToModifies().size() > 0)
					{
						statToModifiers = modifier.getStatToModifies();
						for(StatEnum statToModify : statToModifiers)
						{
							if(!orderedModifiers.containsKey(statToModify))
							{
								orderedModifiers.put(statToModify, new StatModifiers());
							}
							orderedModifiers.get(statToModify).add(modifier);
						}
					}
				}
			}
		}
		
		for(Entry<StatEnum, StatModifiers> entry : orderedModifiers.entrySet())
		{
			applyModifiers(entry.getKey(),entry.getValue());
		}
		
		orderedModifiers.clear();
	}
	
	protected void applyModifiers(final StatEnum stat,StatModifiers modifiers)
	{
		if (modifiers == null)
            return;

        if (!stats.containsKey(stat)) {
            initStat(stat, 0);
        }

        Stat oStat = stats.get(stat);
        int newValue;

        for (StatModifierPriority priority : StatModifierPriority.values()) {
            for (StatModifier modifier : modifiers.getModifiers(priority)) {
                newValue = modifier.apply(oStat.getBase(), oStat.getCurrent());
                oStat.increase(newValue);
            }
        }
	}

	protected void resetStats() {
        synchronized (stats) {
            for (Stat stat : stats.values()) {
                stat.reset();
            }
        }
    }
	
	protected void initStat(StatEnum stat, int value) {
        if (!stats.containsKey(stat))
            stats.put(stat, new Stat(stat, value));
        else {
            stats.get(stat).reset();
            stats.get(stat).set(value);
        }
    }
	
	protected void setStat(StatEnum stat, int value, boolean bonus) {
        if (!stats.containsKey(stat)) {
            stats.put(stat, new Stat(stat, 0));
        }
        stats.get(stat).set(value);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('{');
        sb.append("owner:" + owner.getObjectId());
        for(Stat stat : stats.values())
		{
			sb.append(stat);
		}
		sb.append('}');
		return sb.toString();
	}
}
